package com.zhuimeng.monitor;

import com.zhuimeng.monitor.bean.MethodInfo;
import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

@Activate(group = {CommonConstants.CONSUMER})
public class TpMonitorFilter implements Filter,Runnable {
    Map<String, List<MethodInfo>> methodTime = new ConcurrentHashMap<>();

    public TpMonitorFilter() {
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(this,5,5, TimeUnit.SECONDS);
        Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(new Thread(new RemoveDataThread(methodTime)),10,60, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        Result result = null;
        long taskTime = 0L;
        try{
            long startTime = System.currentTimeMillis();
            result = invoker.invoke(invocation);
            if (result.getException() instanceof Exception){
                throw new Exception(result.getException());
            }
            taskTime =System.currentTimeMillis()-startTime;
        }catch (Exception e){
            e.printStackTrace();
            return result;
        }

        String methodName = invocation.getMethodName();
        List<MethodInfo> methodInfos = methodTime.get(methodName);
        if (methodInfos == null || methodInfos.size() == 0){
            methodInfos = new ArrayList<>();
            methodTime.put(methodName,methodInfos);
        }

        methodInfos.add(new MethodInfo(invocation.getMethodName(),taskTime,System.currentTimeMillis()));

        return result;
    }

    @Override
    public void run() {
        Iterator<Map.Entry<String, List<MethodInfo>>> iterator = methodTime.entrySet().iterator();
        while (iterator.hasNext()){
            Map.Entry<String, List<MethodInfo>> next = iterator.next();
            getTp(next.getKey(),next.getValue());
        }

        System.out.println("**************************************************************");
    }

    private void getTp(String methodName,List<MethodInfo> methodInfos){
        List<MethodInfo> sortInfo = new ArrayList<>();
        long endTime = System.currentTimeMillis();
        long startTime = System.currentTimeMillis()-60000;
        int length = methodInfos.size();
        for (int i=0;i<length;i++){
            MethodInfo methodInfo = methodInfos.get(i);
            if (methodInfo.getEndTime()>=startTime && methodInfo.getEndTime()<=endTime){
                sortInfo.add(methodInfo);
            }
        }

        sortInfo.sort(new Comparator<MethodInfo>() {
            @Override
            public int compare(MethodInfo t1, MethodInfo t2) {
                if (t1.getTime() > t2.getTime()){
                    return 1;
                }
                return 0;
            }
        });
        int size = sortInfo.size();
        int top90Index = (int)(0.9 * size);
        int top99Index = (int)(0.99 * size);
        System.out.println("方法 " + methodName + " 5秒内总调用次数:" + size);
        System.out.println("方法 " + methodName + " top90调用时间:" + methodInfos.get(top90Index).getTime());
        System.out.println("方法 " + methodName + " top99调用时间:" + methodInfos.get(top99Index).getTime());
    }
}
